/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package Yacc;

import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.util.*;
/**
 *
 * @author AranciaCheng
 */
public class AnalysisTable {
    // 分析所需数据
    private String filePath = "../../../testcases/testcase2/tokenstream1.tok"; // 根据class文件写相对路径
    private Stack stack;
    private Map<String,Map<String,ArrayList>> analysisTable;
    private String EPSILON = "\"\"";

    // 基础数据
    private Set<String>[] firstSet;
    public Set<String>[] followSet;
    private String[] nonterminal;
    private String[] orderProductionLeft;
    private ArrayList<String>[] orderProductionRight;

    /**
     * 构造函数
     * @param first   first集
     * @param follow  follow集
     * @param nonTml  非终结符数组
     * @param proL    production左边
     * @param proR    production右边
     */
    public AnalysisTable(Set<String>[] first,Set<String>[] follow,String[] nonTml,
                         String[] proL, ArrayList<String>[] proR){
        stack = new Stack();
        analysisTable = new HashMap();

        firstSet = first;
        followSet = follow;
        nonterminal = nonTml;
        orderProductionLeft = proL;
        orderProductionRight = proR;


    }

    /**
     * 生成分析表
     */
    private boolean generateTable(){
        for(int i=0;i<orderProductionLeft.length;i++){
            String row = orderProductionLeft[i],col = orderProductionRight[i].get(0);
            keyNullCheck("row", row, null);
            int j = getIndex(col);
            if(j!=-1){ // 非终结符
                boolean containEpsilon = false;
                for(String item:firstSet[j]){
                    if(item.equals(EPSILON)) {containEpsilon=true;continue;}
                    if(!keyNullCheck("col", row, item)) return false;
                    analysisTable.get(row).get(item).add(i);
                }
                if(containEpsilon){
                    for(String it:followSet[getIndex(row)]){
                        if(!keyNullCheck("col", row, it)) return false;
                        analysisTable.get(row).get(it).add(i);
                    }
                }
            }else if(!col.equals(EPSILON)){ // 终结符:分是否为EPSILON两种
                if(!keyNullCheck("col", row, col)) return false;
                analysisTable.get(row).get(col).add(i);
            }else if(col.equals(EPSILON)){
//				if(!keyNullCheck("col",row,EPSILON)) return false;
//				analysisTable.get(row).get(EPSILON).add(i);
                for(String it:followSet[getIndex(row)]){
                    if(!keyNullCheck("col", row, it)) return false;
                    analysisTable.get(row).get(it).add(i);
                }
            }

        }
        return true;
    }

    /**
     * 分析filePath所对应的文件,返回语法分析结果T/F
     * @return
     */
    public boolean analyse(){
        if(!generateTable()){
            System.out.println("存在二义性！LL1表创建失败");
            return false;
        };
        printTable();

        stack.push("$");
        stack.push(orderProductionLeft[0]);
        String token="";
        try{
            LineNumberReader br = new LineNumberReader(new FileReader(filePath));
            token = br.readLine();
            while(true){
                System.out.print(token+"\t");
                System.out.println(stack);
                String top = stack.peek().toString();

                if(!top.equals("$") && !token.equals("$")) break;

                if(token==null) token="$";
                if(getIndex(top)==-1 && token.equals(top)){
                    match(token);
                    stack.pop();
                    token=br.readLine();
                }else if(getIndex(top)!=-1 && isTerminal(token)&& analysisTable.get(top).get(token)!=null){
                    int n = Integer.parseInt(analysisTable.get(top).get(token).get(0).toString());
                    stack.pop();
                    for(int k=orderProductionRight[n].size()-1;k>=0;k--){
                        stack.push(orderProductionRight[n].get(k));
                    }
                }else {
                    System.out.println("analyse ERROR!");
                    return false;
                }
            }
        }catch(IOException e){ e.printStackTrace();}
        while(stack.peek().toString().equals("$")){stack.pop();}
        if(stack.pop().equals("$")&& token.equals("$")) return true;
        return false;
    }

    // print
    public void printTable(){
        System.out.println("\nLL1 table:");
        for(String item:analysisTable.keySet()){
            System.out.print(item+":");
            System.out.println(analysisTable.get(item));
        }
        System.out.println();
    }

    // tools
    boolean isTerminal(String a){ // 判断是否为终结符
        for(int i=0;i<orderProductionRight.length;i++){
            for(String item:orderProductionRight[i]){
                if(item.equals(a) && getIndex(item)==-1) {
                    return true;
                }
            }
        }
        if(a=="$") return true;
        return false;
    }

    private boolean keyNullCheck(String mode,String row,String col){ // 判断之前的Map是否存在对应的Key,不存在则新生成

        if(mode.equals("row")){
            if(analysisTable.get(row)==null) analysisTable.put(row, new HashMap());
            return true;
        }else if(mode.equals("col")){
            Object tdObj = analysisTable.get(row).get(col);
            if(tdObj!=null){
                int td = Integer.parseInt(analysisTable.get(row).get(col).get(0).toString());
                String rule = orderProductionLeft[td] +"->"+ orderProductionRight[td].toString();
                System.out.println("ERROR:"+"["+row+","+col+"]"+" has exist "+rule);
                return false;
            }else{
                analysisTable.get(row).put(col, new ArrayList());
                return true;
            }
        }
        return false;
    }

    private int getIndex(String a){ // 从非终结符数组中查找对应字符串a的下标
        for(int i=0;i<nonterminal.length;i++){
            if(nonterminal[i].equals(a)) return i;
        }
        return -1;
    }


    // 形式意义上的2个函数，实际没用
    private void match(String a){
        System.out.println("match "+a);
    }

    private void generate(){

    }


}
